Dispatch the CSA Compressor gated pooling to the cudnn-frontend fused kernels (THD) - #5984
Dispatch the CSA Compressor gated pooling to the cudnn-frontend fused kernels (THD)#5984zkyue wants to merge 2 commits into
Conversation
|
Hi @zkyue Thanks for your contribution! I think it is better to put the kernels in cudnn-frontend like other CSA/HCA fused kernels. Is it convenient for you to do so, or do you need our help to port the kernel? |
|
@hxbai Sure, happy to do that — the kernels are self-contained CuTe DSL and should map cleanly onto the cudnn-frontend python API structure (we've contributed there before). Plan: I'll open a PR against cudnn-frontend porting the fwd+bwd kernels (APIBase-style wrapper, THD semantics, tests), then rework this PR into a thin dispatch that uses the cudnn-frontend implementation when available, keeping the eager fallback. Will link the kernel PR here once it's up. |
|
@hxbai The cudnn-frontend kernel PR is up: NVIDIA/cudnn-frontend#427 (fwd+bwd kernels, APIBase-style wrapper, THD semantics, 40 tests; outputs bit-identical to the kernels in this PR). Once it lands I'll rework this PR into the thin dispatch that uses the cudnn-frontend implementation when available, keeping the eager fallback. |
…rom Megatron-LM) (#427) * CSA: add fused Compressor forward+backward CuTe-DSL kernels Port the fused CSA/HCA Compressor gated-pooling kernels from Megatron-LM (NVIDIA/Megatron-LM#5984) into the FE-OSS Python API, per the maintainer request in NVIDIA/Megatron-LM#5984 (comment). One forward and one backward CuTe-DSL kernel fuse the THD gated-softmax pooling region (gather -> +APE -> overlap-window transform -> fp32 softmax -> gated weighted sum -> bf16 cast). Kernel math is unchanged from the Megatron original (verified bitwise on forward/dKV/dScore); the interface is reshaped to the APIBase pattern: CSACompressorForward / CSACompressorBackward classes, csa_compressor_forward_wrapper / csa_compressor_backward_wrapper, a new python/cudnn/csa package, docs, and fe_api tests (numerics vs fp32/upstream eager references and an fp64 oracle, ragged packs, static-capacity padding, run-to-run determinism, CUDA-graph capture/replay, check_support boundaries). Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> * CSA compressor: vectorize forward bf16 access (32-bit, CuTe autovec_copy) Widen every bf16 load/store in the fused Compressor forward kernel from scalar (16-bit) to paired 32-bit accesses: each thread now owns 2 adjacent head dims and moves its window slices through 32-bit universal copies (cute.autovec_copy over register fragments; cute.assume makes the alignment provable). The per-lane fp32 math is unchanged and in the same order, so the forward output stays bitwise identical to the previous kernel (re-verified against the Megatron-LM original on the same 5 THD shape-mix gate as the original port). Odd head_dims keep a scalar (vec == 1) instantiation of the same kernel; the head_dim 128/512 production shapes take vec == 2. The launch schedule moves from (rows_per_cta=4, threads=128) to one row per CTA with 64-thread column groups, which widens the sub-wave grids that limit the small shapes. Measured (nsys pure kernel time, B200, ratio=4 coff=2, THD packs of 8192-token sequences, forward kernel only): shape before after speedup 1x8192 d128 6.0 us 4.5 us 1.36x 3x8192 d128 12.6 us 10.0 us 1.26x 1x8192 d512 16.0 us 12.4 us 1.29x 3x8192 d512 42.1 us 35.0 us 1.20x Alternatives measured and rejected on the same matrix (all bitwise-equal): a PTX-unpack vec2 prototype (slower than the pure-DSL version: 4.7/10.5/12.9/35.7 us), and 64/128/256-bit per-thread vectors, which cut executed instructions but lose to register pressure and occupancy (80/147/255 regs vs 48; the 256-bit variant spills). Registers stay spill-free at 48 (previous kernel: 40). Tests: numerics shape matrix extended with an odd head_dim case to cover the scalar-layout instantiation, and a check_support rejection for head_dims beyond the launch bound. Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> * CSA compressor: fold dKV/dScore zero-init into the backward kernel The backward previously required zero-initialized dKV/dScore buffers: the kernel only wrote consumed positions, and two tensor-wide bf16 fill kernels (torch.zeros_like) supplied the zeros everywhere else. Those fills cost as much DRAM traffic as the kernel's own stores. The kernel now writes every position itself: consumed positions get their gradients as before (disjoint, atomic-free stores), and each never-consumed slot class gets an exact zero from a unique natural owner, keeping all stores disjoint and dKV/dScore bitwise run-to-run deterministic: - first-half columns of each segment's last block's own tokens (coff == 2; no next block consumes them) -> that last block; - per-segment tail tokens (seqlen % ratio, both halves) -> the segment's last block; - all tokens of segments with zero output blocks (seqlen < ratio) -> CTA column bidx == 0; - tokens beyond cu_seqlens[-1] (static token-capacity padding of the gradient buffers, the CUDA-graph case) -> grid-strided across CTA columns. The backward wrapper allocates grad_kv/grad_score with torch.empty_like instead of torch.zeros_like (the fp32 dAPE fill stays: it is the atomic accumulator). When total_comp == 0 the kernel cannot launch, so the wrapper falls back to zeroed allocations to preserve autograd's exact-zero semantics; the class API documents the same caveat. Measured on the backward region (kernel + remaining fills vs kernel + three fills before), B200, ratio=4 coff=2, THD packs of 8192-token sequences; nsys = sum of kernel durations per iteration, wall = CUDA events around the wrapper call: shape nsys before -> after wall before -> after 1x8192 d128 15.5 -> 12.8 us (1.21x) 56.2 -> 47.2 us (1.19x) 3x8192 d128 29.9 -> 22.2 us (1.35x) 61.8 -> 54.6 us (1.13x) 1x8192 d512 34.2 -> 22.8 us (1.50x) 67.9 -> 57.3 us (1.19x) 3x8192 d512 90.9 -> 66.0 us (1.38x) 111.6 -> 101.8 us (1.10x) The zero-writes cost the kernel 8 registers (64 -> 72, occupancy 44% -> 41% at 3x8192 d512) and a small amount of extra store traffic, repaid several times over by dropping the two whole-tensor fills. dKV/dScore remain bitwise identical to the Megatron-LM original on the 5-shape port gate and to the fp32 eager reference on every test shape. Tests: NaN-canary suite proving the kernel fully overwrites uninitialized buffers (ragged, degenerate short segments, all-tiny packs, head_dim 512, static-capacity padded rows) bitwise against zero-initialized runs and the eager reference; a zeros-fallback test for packs where no segment reaches ratio tokens. The existing CUDA-graph replay test covers the token-capacity padding class (it fails without the grid-strided sweep). Docs: csa.md updated (buffer contract, fill count, perf tables refreshed for both this commit and the forward vectorization). Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> * Address review feedback: docs bounds, lint, warning stacklevel - docs: list the total_comp * head_dim < 2**31 and total_comp > 0 with total_tokens < ratio support boundaries already enforced in check_support - docs: run the compressor tests from test/python per repo convention - csa/__init__.py: spell out __all__ as an explicit literal (Ruff PLE0604) - compressor/__init__.py: sort __all__ (Ruff RUF022) - compressor/api.py: add stacklevel=2 to the deterministic-mode RuntimeWarning Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> * CSA compressor: rewrite graph benchmark to fwd-only + fwd+bwd total graphs Address review feedback on the PR #427 fairness benchmark (benchmark/csa/bench_csa_compressor.py). - Drop the subtraction-derived backward-graph estimate. Graph variants are now two directly measured, symmetric columns for both eager and fused: a forward-only graph (eager under no_grad) and a forward+backward total graph. - Capture the eager fwd+bwd graph with stable, pre-allocated zero .grad buffers (the supported torch CUDA-graph pattern): the captured region zeros them in place, then runs forward + autograd backward, so every replay accumulates into a zeroed buffer -- numerically identical to a single fresh backward. A per-shape graph-vs-fresh-backward cross-check is printed (all shapes bitwise-equal). - The fused total graph captures the forward wrapper immediately followed by the backward wrapper. - Emit both the per-call and graph tables from a single run; graph speedups are eager/fused of the displayed us, truncated to one decimal (never rounded up). The backward replay is reported only as ~total-fwd (a reference), never as a column. Not collected by pytest; black -l160 clean. Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> * docs(csa): refresh graph table to fwd/total columns; soften wording Address review feedback on the CSA compressor performance tables (docs/fe-oss-apis/csa.md). - Replace the CUDA-graph table (which published a subtraction-derived backward column) with two directly measured columns: eager/fused forward-only graph and eager/fused forward+backward total graph. No backward-graph column; backward is noted only as ~total-fwd, never as a measured value. - Refresh both the per-call and graph tables from a single run of the benchmark harness; graph speedups are eager/fused of the displayed us, truncated to one decimal. - State that capture collapses each side's per-op launches into a single replay rather than removes launch/host overhead; say less launch-bound rather than compute-bound. - Note how the re-run reproduces the previously published per-call wall clock, and document the eager-backward capture basis (stable zero .grad buffers). Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> * bench(csa): guard speedup division, dedupe leaf construction, ruff nits Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> * CSA compressor: widen the validated envelope to coff in {1, 2} The kernels are already generic over coff — for coff=1 the window is the block's own ratio tokens (no overlap transform, always valid); only the check_support gate restricted the APIs to the production coff=2 form. Widen the gate to coff in {1, 2} (ratio stays gated at 4), update the error message and the envelope prose in api.py / docs / README, and parametrize the tests over both coff forms: numerics vs the fp32/upstream/fp64 eager references (the eager reference already implements coff=1 faithfully — it skips the overlap transform), static- capacity padding, replay determinism, empty outputs, NaN-canary zero-writes, deterministic-mode error paths, CUDA-graph capture, class-vs-wrapper equivalence, and check_support accept/reject boundaries (new coff=0 / coff=3 rejects; a new empty-segment shape covers both coff forms). No kernel changes. Addresses hxbai's coff=1 question on the PR. Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> * CSA: add missing docstrings across the compressor Python files Bring the PR's Python docstring coverage over CodeRabbit's 80% pre-merge gate: module docstrings for the csa package/compressor __init__ files and one-line docstrings for the remaining undocumented helpers in api.py (cache/ctor/compile plumbing), compressor_sm100.py (launcher ctors), the test helpers, and the benchmark helpers. interrogate 1.7.0 over the PR's six CSA Python files: 69.4% -> 100%. Docstrings only — no logic, kernel, or launch-path changes. Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> * CSA compressor: add dedicated ratio=128 kernels (forward+backward) with ratio dispatch The generic CSA compressor kernels keep the whole coff * ratio pooling window in per-thread registers; past ratio ~32 that hits the 255-register wall and spills kilobytes of local memory per thread, so ratio=128 needs dedicated kernels rather than a lifted gate. This adds them behind the same public API: check_support now admits ratio in {4, 128} x coff in {1, 2} (ratio=128 additionally gated to head_dim in {128, 512}, the hardware-validated set) and the wrappers and class APIs route to the matching kernel family by ratio transparently. Design: the forward streams the window with a chunked online softmax (one CTA per output row, per-column (max, denom, acc) triples merged in one fixed smem order); its launch schedule is bucketed by output-row count (small/default/large, all precompiled for CUDA-graph safety) and per bucket selects two-phase accumulation and an ex2.approx fast exp where measured faster. The backward stages each row's window through shared memory chunk-parallel, fuses the per-chunk den/S partial sums into the same pass, merges partials in a fixed chunk order, and stores gradients with a hoisted 1/den multiply — keeping kernel-side zero-writes to never-consumed dKV/dScore slots and fp32-atomic dAPE exactly as at ratio=4. ptxas (sm_100a): forward 32-51 registers, backward 48-128, 0 spill / 0 stack across all 16 shipped (config, schedule) kernels (reproducer: benchmark/csa/reg_probe_csa_compressor_r128.py). Numerics contract, per ratio family (docs/fe-oss-apis/csa.md): ratio=4 keeps its bitwise contract UNCHANGED — dKV/dScore bit-identical to the fp32-intermediate eager reference, at coff 1 and 2. ratio=128 is deterministic + faithful to that same fp32-intermediate eager reference: bitwise run-to-run determinism of out/dKV/dScore (NaN-prefill replay tested); the same values within final-bf16 rounding at the gate tolerances (differing elements <= max(1, 0.1%), max_abs <= 1.6e-2, calibrated on the gate's documented input distribution — bf16 deviations scale 2^k with 2^k inputs while the fp32 intermediates stay finite); the eager reference's non-finite propagation (finite inputs that overflow its fp32 intermediates poison both sides alike, with the stated caveat that the fused order saturates earlier near fp32 max — un-normalized chunk partials); and, on inputs whose fp32 intermediates stay finite in both evaluation orders, fp64-oracle parity (at least as close to an fp64 oracle as the eager reference). The reduction reorders and fast-exp buckets were each adopted on a measured win and are covered by that contract. Performance (nsys isolated GPU kernel time, 1x B200, vs the fp32-intermediate eager reference region on identical inputs): forward 13.2-44.4x, backward 7.4-21.9x across coff {1, 2} x head_dim {128, 512} x 8k-131k tokens; e.g. coff=2, d=128, 65k tokens: fwd 726.3 -> 16.4 us (44.4x), bwd 960.0 -> 61.2 us (15.7x). Full tables with methodology in docs/fe-oss-apis/csa.md. Validation (B200, CC 10.0): the committed 21-case contract gate (benchmark/csa/gate_csa_compressor_r128.py) passes 21/21 with shipped schedule coverage asserted (forward 10/10, backward 6/6 buckets); pytest fe_api/csa/test_CSA_compressor.py: 88 passed, 1 skipped at the default L0 level and 98 passed, 1 skipped with -m "L0 or L1" (both ratio families; the ratio=4 rows, including the coff=1 envelope, stay on their bitwise assertions). New tests cover the ratio=128 dispatch envelope (schedule selection at every nb_total bucket boundary; every shipped (config, schedule) kernel executed against the full contract at L1), exact-zero assertions on every never-consumed dKV/dScore slot class in the NaN-canary, CUDA-graph capture/replay for the new family, and grad_ape zeroing-ownership regressions. Signed-off-by: zky <51477259+zkyue@users.noreply.github.com> --------- Signed-off-by: zky <51477259+zkyue@users.noreply.github.com>
…ressor The fused forward+backward kernels for the gated-pooling region of Compressor._forward_thd now live in the cudnn-frontend Python package (cudnn.csa.compressor, cudnn-frontend PR NVIDIA#427). Megatron-side this is a thin additive dispatch: maybe_compress_thd_fused() returns the pooled tensor when the frontend is importable and the configuration is supported (THD non-pre-grouped path, compress_ratio == 4, bf16 kv/score, fp32 ape, compute capability 10.0, int32 flat offsets) and None otherwise, in which case the eager region runs unchanged. SBHD and the pre-grouped CP-prep path are untouched. Frontend availability is probed by importing the concrete entry points (csa_compressor_forward_wrapper / csa_compressor_backward_wrapper), not by version comparison: nvidia-cudnn-frontend installs that predate the CSA compressor API lack cudnn.csa and keep the eager path, as does any import failure (e.g. the DSL extra missing). The dispatch also keeps the eager path under torch.use_deterministic_algorithms(True) (dAPE fp32 atomics) and under torch.compile tracing (raw-pointer launch path is not traceable). MCORE_CSA_FUSED_COMPRESSOR=0 disables the dispatch entirely. compress_ratio == 128 is functionally supported by the frontend kernels but stays on the eager path until tuned (see issue NVIDIA#5968). Addresses NVIDIA#5968. Signed-off-by: zky <kaiyue.zhou@z.ai>
The kernels themselves are validated in cudnn-frontend (PR NVIDIA#427); these tests cover the Megatron-side wiring: numerics of the dispatched fused region vs an fp32-intermediate eager reference (bitwise dKV/dScore, forward within one bf16 rounding step) and vs the verbatim upstream eager numerics (tolerance) over ragged THD packs including segments shorter than ratio; fixed_total_comp static-capacity padding rows (including that nonzero padding-row gradients are ignored); dispatch gating and eager fallback (kill switch, missing/old cudnn-frontend, deterministic mode, ratio 128, non-bf16, layout, empty output), plus Compressor._forward_thd-level integration (fused engages and matches eager, bitwise eager fallback without the frontend, gradients flow). The module is marked launch_on_gb200 for the CC 10.0 CI lane and skips cleanly without CUDA, without a cudnn-frontend that provides cudnn.csa, or off compute capability 10.0. Addresses NVIDIA#5968. Signed-off-by: zky <kaiyue.zhou@z.ai>
8217542 to
e073b28
Compare
|
cudnn-frontend #427 merged this morning ( Force-pushed |
|
/claude strict-review |
There was a problem hiding this comment.
Strict review passed — no significant issues found.
Scope: thin, additive dispatch shim (+732/−37) routing the THD non-pre-grouped CSA gated-pooling region to the cudnn-frontend fused kernels, with the eager region preserved verbatim as the reference/fallback.
Verified sound:
- Autograd arity —
forwardtakes 9 non-ctx args;backwardreturns exactly 9 grads (3 real + 6None). Correct. - Shape parity — fused
out.unsqueeze(1)→(total_comp, 1, head_dim), identical to the eager(kv_grouped * weights).sum(dim=1). - Gating invariants —
ratio == 4 ⟺ coff == 2 ⟺ overlapare locked together in__init__, so the fused path cannot be reached with a coff/overlap mismatch. Gates also correctly cover dtype (bf16 kv/score, fp32 ape), device (CC 10.0, cached), int32-offset overflow (total * coff * head_dim < 2**31), deterministic mode, andtorch.compiletracing. - No hot-path sync — all dispatch checks are host-side (
.shape, env read, cached capability lookup); no CPU↔GPU sync introduced. On non-CC-10.0 hardware the probe short-circuits to eager after a one-time cached import. - Import safety — the frontend import is lazy inside
_get_frontend();csa.py's import chain never fails on a missing/old/partial frontend. - Backward compat — no renamed/removed args, no checkpoint or API signature changes. H100/A100 (CC ≠ 10.0) stay bit-identical on eager. The
dsv4_hybrid_fusedfunctional case is commented out in the gb200 recipe, so no golden-value impact. - Unused-variable check — all new identifiers have real use paths;
_frontend_erroris a documented debugging aid.
One point for maintainer decision (not a defect): the fused path is on by default, so GB200 users with cudnn-frontend ≥ 1.27 get a silent numerics change (fp32-intermediate vs the eager bf16-weight multiply — documented as at-least-as-accurate against an fp64 oracle). The author has already flagged this and offered to flip to opt-in; noting only so the choice is made deliberately.
Risk: low. Additive, capability-gated, no-op against any cudnn-frontend predating the CSA API, and covered by the new dispatch/gating/fallback tests. LGTM.
What (reworked per review)
Addresses #5968. Reworked as discussed with @hxbai: the fused kernels themselves have
moved to cudnn-frontend — NVIDIA/cudnn-frontend#427 (merged into
developatb950af1, 2026-07-30) adds them behind the FE-OSSAPIBasepattern (cudnn.csa.compressor,CSACompressorForward/Backward+high-level wrappers) — and this PR is now the thin Megatron-side dispatch only:
Compressor._forward_thd(THD packed, non-pre-grouped path) tries the fused fastpath for the gated-softmax pooling region — gather-index build, gather,
+ APE,overlap-window transform (
coff == 2), fp32 softmax, gated weighted sum — and keepsthe existing eager implementation as the semantic reference and fallback for every
unsupported configuration. One fused compute kernel per direction (plus a small
dAPEzero-init in backward) instead of ~40 forward / ~50 backward eager launches.the pre-grouped CP-prep input path are untouched.
Compared to the previous revision of this PR, the ~1000-line kernel module and the
benchmark harness are gone (they live in cudnn-frontend #427, harness included in its
test/bench assets); what remains is a ~240-line dispatch shim, the
csa.pyedit, and atrimmed test file: +732 / −37 vs
dev(previously +1930 / −37).Dependency
CSA: add fused Compressor forward+backward CuTe-DSL kernels (ported from Megatron-LM) cudnn-frontend#427, merged into
developatb950af1(2026-07-30). Thefused path activates when the installed cudnn-frontend provides
cudnn.csa— i.e. asource install of
develop>=b950af1, or the upcomingnvidia-cudnn-frontend1.27pip release (expected early August) — otherwise the dispatch silently keeps the eager
path. This includes the frontend's
nvidia-cutlass-dslruntime dependency (thefrontend's
cutedslextra). No hard dependency is added to Megatron: availabilityis probed at dispatch time by importing the concrete entry points
(
cudnn.csa.compressor.csa_compressor_forward_wrapper/..._backward_wrapper) —capability detection, not version comparison.
nvidia-cudnn-frontendinstalls thatpredate the API simply lack
cudnn.csa, and any import failure (missing package,missing DSL extra, partial install) silently keeps the eager path;
csa.py's importchain never fails because of the frontend.
torch.autograd.Functionaround thefrontend's forward/backward wrappers); the frontend APIs are pure
kernels-plus-validation.
Dispatch / gating (unchanged semantics vs the previous revision)
The fast path engages only for: THD packed non-pre-grouped path,
compress_ratio == 4(
coff == 2, the production CSA/HCA configuration), bf16kv/score, fp32ape,compute capability 10.0 (the frontend's validated envelope), int32 flat offsets
(
total_tokens * coff * head_dim < 2**31). Everything else — SBHD, the pre-groupedCP-prep path,
compress_ratio == 128(functionally supported by the frontend kernels,stays on eager until tuned), missing/old frontend, other devices — keeps the eager
implementation.
MCORE_CSA_FUSED_COMPRESSOR=0disables the dispatch entirely. Thedispatch also keeps the eager path under
torch.use_deterministic_algorithms(True)(
dAPEis accumulated with fp32 atomics in the fused backward) and undertorch.compiletracing (the frontend launch path takes raw pointers; eager lets thecompiler fuse the region itself). CUDA graphs: capture-compatible after a one-step
eager warmup per
(ratio, head_dim, coff)configuration (a first call that would JITunder capture raises loudly, per the frontend); the dispatch passes the caller's static
fixed_total_compcapacity through without device synchronization.Numerics
The numerics contract is the frontend kernels' (measured and tested in
NVIDIA/cudnn-frontend#427; original analysis in #5968): all arithmetic fp32 with a
single final bf16 rounding,
mul.rn/fma.rnpinned in PTX. vs an fp32-intermediateeager reference:
dKV/dScorebit-identical, forward within one bf16 roundingstep. Not bit-identical to the current eager region (which rounds softmax weights to
bf16 and multiplies in bf16) but at least as accurate against an fp64 oracle on every
tested output. Forward,
dKV,dScoreare bitwise run-to-run deterministic;dAPEisnot (fp32 atomics) — hence the deterministic-mode fallback above. Incoming gradients on
static-capacity padding rows are ignored (they are tail padding, not consumed
downstream); never-consumed input elements get exact zeros, matching autograd. These
gates are re-verified here at the dispatch level (see Tests).
Performance
The kernels this PR dispatches to are the ones measured in NVIDIA/cudnn-frontend#427
(same B200 methodology as before; the port also picked up two additional optimization
commits there — forward 32-bit vectorized access and backward kernel-side zero-writes —
so the numbers are better than this PR's previous revision). From #427, isolated GPU
kernel time (nsys, sum of kernel durations, 50 iterations after 20 warmup; THD packs of
8192-token sequences,
ratio = 4,coff = 2, bf16, vs the verbatim eager region ofCompressor._forward_thd):Wall-clock numbers, the hardware-ceiling audit (DRAM traffic within 1% of algorithmic
bytes), and per-commit bitwise gates are in #427's description.
Tests
tests/unit_tests/transformer/experimental_attention_variant/test_csa_fused_compressor.py— trimmed to the Megatron-side wiring (kernel-level coverage — zero-write ownership,
CUDA-graph capture/replay, determinism,
coff == 1, fp64 oracle — lives in #427's testsuite):
before (
dKV/dScorebitwise vs an fp32-intermediate reference; forward within onebf16 rounding step; tolerance vs verbatim upstream numerics) over ragged THD packs
including segments shorter than
ratio;fixed_total_compstatic-capacity padding through the dispatch (forward semantics +ignored padding-row gradients);
cudnn.csa→ silent eager, verified bitwise-identical to the kill-switch path at theCompressor._forward_thdlevel), deterministic mode (dispatch falls back; enablingdeterministic mode between forward and backward raises loudly in the frontend),
ratio == 128, non-bf16, unexpected layout, empty output;Compressor._forward_thdintegration: fused engages (spy), matches eager, gradientsflow to inputs and
ape.The module keeps
pytestmark = pytest.mark.launch_on_gb200; without CUDA, without acudnn-frontend that provides
cudnn.csa, or off CC 10.0 every test skips cleanly (theGB200 CI lane needs
nvidia-cudnn-frontend>= 1.27 — the first release containing#427 — plus its
cutedslextra to actually exercise the fused path; until then thetests skip rather than fail).
Full runs on 1×B200 with cudnn-frontend
develop@b950af1(the #427 merge)installed from source: the new test file
8 passed; the related suites (
test_attention_variant_csa.py,test_csa_cp_layout_kernels.py,test_csa_cp_utils.py) with the fused dispatch live:123 passed, 1 skipped (needs ≥2 ranks), 0 failed. With no cudnn-frontend installed:
8 skipped, related suites unaffected (eager path is untouched).
Notes
MCORE_CSA_FUSED_COMPRESSOR=0), as in the previous revision — happy to flip toopt-in if you prefer.
develop@b950af1, 2026-07-30), sothe ordering constraint from the previous revision is satisfied; this PR remains a
no-op (eager everywhere) against any cudnn-frontend that predates the CSA API.
dAPEreduction for theratio=4 backward, wider arch enablement after validation. (The dedicated
compress_ratio == 128kernels, previously listed here, landed in [QUESTION] Does the zero-out operation conduct during the model initialization and affect reproducibility? #427 itself.)